home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / ARP.C < prev    next >
Text File  |  1993-09-19  |  11KB  |  375 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  * mods for WAMPES by DB3FL 1990,1991
  4.  * using ARP_FILE_VERSION 3 from Oct 91 on. Now included the mode of the
  5.  * ax25 connection (stored in "->flags" - same value as defined in iface.h)
  6.  */
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "iface.h"
  12. #include "enet.h"
  13. #include "ax25.h"
  14. #include "icmp.h"
  15. #include "ip.h"
  16. #include "arp.h"
  17. #include "files.h"
  18.  
  19. struct arp_tab *Arp_tab = NULLARP;
  20.  
  21. struct arp_stat Arp_stat;
  22.  
  23. /* Copy a host format arp structure into mbuf for transmission */
  24. static struct mbuf * near
  25. htonarp(struct arp *arp)
  26. {
  27.     struct mbuf *bp = alloc_mbuf(ARPLEN + (2 * uchar(arp->hwalen)));
  28.     char *buf = bp->data;
  29.  
  30.     buf = put16(buf,arp->hardware);
  31.     buf = put16(buf,arp->protocol);
  32.     *buf++ = arp->hwalen;
  33.     *buf++ = arp->pralen;
  34.     buf = put16(buf,arp->opcode);
  35.     memcpy(buf,arp->shwaddr,arp->hwalen);
  36.     buf += arp->hwalen;
  37.     buf = put32(buf,arp->sprotaddr);
  38.     memcpy(buf,arp->thwaddr,arp->hwalen);
  39.     buf += arp->hwalen;
  40.     buf = put32(buf,arp->tprotaddr);
  41.  
  42.     bp->cnt = buf - bp->data;
  43.     return bp;
  44. }
  45.  
  46. /* Send an ARP request to resolve IP address target_ip */
  47. static void near
  48. arp_output(struct iface *iface,int16 hardware,int32 target)
  49. {
  50.     struct arp arp;
  51.     struct mbuf *bp;
  52.     struct arp_type *at = &Arp_type[hardware];
  53.  
  54.     if(iface->output != NULLFP) {
  55.         arp.hardware = hardware;
  56.         arp.protocol = at->iptype;
  57.         arp.hwalen = at->hwalen;
  58.         arp.pralen = sizeof(int32);
  59.         arp.opcode = ARP_REQUEST;
  60.         memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  61.         arp.sprotaddr = iface->addr;
  62.         memset(arp.thwaddr,0,at->hwalen);
  63.         arp.tprotaddr = target;
  64.         Arp_stat.outreq++;
  65.  
  66.         bp = htonarp(&arp);
  67.         if(iface->forw != NULLIF) {
  68.             iface = iface->forw;
  69.         }
  70.         (*iface->output)(iface,at->bdcst,iface->hwaddr,at->arptype,bp);
  71.     }
  72. }
  73.  
  74. /* Resolve an IP address to a hardware address; if not found,
  75.  * initiate query and return NULLCHAR.  If an address is returned, the
  76.  * interface driver may send the packet; if NULLCHAR is returned,
  77.  * res_arp() will have saved the packet on its pending queue,
  78.  * so no further action (like freeing the packet) is necessary.
  79.  */
  80. char *
  81. res_arp(
  82. struct iface *iface,    /* Pointer to interface block */
  83. int16 hardware,         /* Hardware type */
  84. int32 target,           /* Target IP address */
  85. struct mbuf *bp)        /* IP datagram to be queued if unresolved */
  86. {
  87.     struct arp_tab *arp;
  88.  
  89.     if((arp = arp_lookup(hardware,target)) != NULLARP) {
  90.         struct ip ip;
  91.  
  92.         if(arp->state == ARP_VALID)
  93.             return arp->hw_addr;
  94.  
  95.         /* Earlier packets are already pending, kick this one back
  96.          * as a source quench
  97.          */
  98.         ntohip(&ip,&bp);
  99.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  100.         free_p(bp);
  101.     } else {
  102.         /* Create an entry and put the datagram on the
  103.          * queue pending an answer
  104.          */
  105.         arp = arp_add(target,hardware,NULLCHAR,0,0);
  106.         enqueue(&arp->pending,bp);
  107.         arp_output(iface,hardware,target);
  108.     }
  109.     return NULLCHAR;
  110. }
  111.  
  112. /* Handle incoming ARP packets. This is almost a direct implementation of
  113.  * the algorithm on page 5 of RFC 826, except for:
  114.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  115.  *    pending a reply to our ARP request.
  116.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  117.  * 3. Requests for IP addresses listed in our table as "published" are
  118.  *    responded to, even if the address is not our own.
  119.  */
  120. void
  121. arp_input(struct iface *iface,struct mbuf *bp)
  122. {
  123.     struct arp arp;
  124.     struct arp_tab *ap;
  125.     struct arp_type *at;
  126.  
  127.     Arp_stat.recv++;
  128.  
  129.     if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  130.         return;
  131.     if(arp.hardware >= NHWTYPES){
  132.         /* Unknown hardware type, ignore */
  133.         Arp_stat.badtype++;
  134.         return;
  135.     }
  136.     at = &Arp_type[arp.hardware];
  137.     if(arp.protocol != at->iptype){
  138.         /* Unsupported protocol type, ignore */
  139.         Arp_stat.badtype++;
  140.         return;
  141.     }
  142.     if((unsigned)(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  143.         /* Incorrect protocol addr length (different hw addr lengths
  144.          * are OK since AX.25 addresses can be of variable length)
  145.          */
  146.         Arp_stat.badlen++;
  147.         return;
  148.     }
  149.     if(arp.sprotaddr == 0L || arp.tprotaddr == 0L){
  150.         /* We are going to dead-end references for [0.0.0.0], since
  151.          * experience shows that these cause total lock up -- N1BEE
  152.          */
  153.         Arp_stat.badaddr++;
  154.         return;
  155.     }
  156.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  157.         /* This guy is trying to say he's got the broadcast address! */
  158.         Arp_stat.badaddr++;
  159.         return;
  160.     }
  161.  
  162.     /* If this guy is already in the table, update its entry
  163.      * unless it's a manual entry (noted by the lack of a timer)
  164.      */
  165.     ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  166.  
  167.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  168.       && dur_timer(&ap->timer) != 0){
  169.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,0);
  170.     }
  171.  
  172.     /* See if we're the address they're looking for */
  173.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  174.         if(ap == NULLARP)       /* Only if not already in the table */
  175.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0,0);
  176.         if(arp.opcode == ARP_REQUEST){
  177.             /* Swap sender's and target's (us) hardware and protocol
  178.              * fields, and send the packet back as a reply
  179.              */
  180.             memcpy(arp.thwaddr,arp.shwaddr,arp.hwalen);
  181.             /* Mark the end of the sender's AX.25 address
  182.              * in case he didn't
  183.              */
  184.             if(arp.hardware == ARP_AX25)
  185.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  186.  
  187.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  188.             arp.tprotaddr = arp.sprotaddr;
  189.             arp.sprotaddr = iface->addr;
  190.             arp.opcode = ARP_REPLY;
  191.             bp = htonarp(&arp);
  192.  
  193.             if(iface->forw != NULLIF)
  194.                 iface = iface->forw;
  195.             (*iface->output)(iface,arp.thwaddr,iface->hwaddr,at->arptype,bp);
  196.             Arp_stat.inreq++;
  197.         } else {
  198.             Arp_stat.replies++;
  199.         }
  200.     } else if(arp.opcode == ARP_REQUEST
  201.       && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  202.       && ap->pub){
  203.         /* Otherwise, respond if the guy he's looking for is
  204.          * published in our table.
  205.          */
  206.         memcpy(arp.thwaddr,arp.shwaddr,arp.hwalen);
  207.         /* Mark the end of the sender's AX.25 address
  208.          * in case he didn't
  209.          */
  210.         if(arp.hardware == ARP_AX25)
  211.             arp.thwaddr[ALEN] |= E;
  212.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  213.         arp.tprotaddr = arp.sprotaddr;
  214.         arp.sprotaddr = ap->ip_addr;
  215.         arp.opcode = ARP_REPLY;
  216.  
  217.         bp = htonarp(&arp);
  218.         if(iface->forw != NULLIF)
  219.             iface = iface->forw;
  220.         (*iface->output)(iface,arp.thwaddr,iface->hwaddr,at->arptype,bp);
  221.         Arp_stat.inreq++;
  222.     } else if(arp.opcode == RARP_REQUEST) {
  223.         for(ap = Arp_tab; ap != NULLARP; ap = ap->next)
  224.             if(memcmp(ap->hw_addr,arp.thwaddr,at->hwalen) == 0)
  225.                 goto found;
  226. found:
  227.         if(ap != NULLARP && ap->pub) {
  228.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  229.             arp.tprotaddr = ap->ip_addr;
  230.             arp.sprotaddr = iface->addr;
  231.             arp.opcode = RARP_REPLY;
  232.  
  233.             bp = htonarp(&arp);
  234.             if(iface->forw != NULLIF)
  235.                 iface = iface->forw;
  236.             (*iface->output)(iface,arp.thwaddr,iface->hwaddr,REVARP_TYPE,bp);
  237.             Arp_stat.inreq++;
  238.             }
  239.     }
  240. }
  241.  
  242. /* Add an IP-addr / hardware-addr pair to the ARP table */
  243. struct arp_tab *
  244. arp_add(
  245. int32 ipaddr,           /* IP address, host order */
  246. int16 hardware,         /* Hardware type */
  247. char *hw_addr,          /* Hardware address, if known; NULLCHAR otherwise */
  248. int pub,                /* Publish this entry? */
  249. int flags)                /* ax25 connection mode */
  250. {
  251.     struct arp_tab *ap;
  252.     struct arp_type *at = &Arp_type[hardware];
  253.  
  254.     if(hardware >= NHWTYPES) {
  255.         return NULLARP;         /* Invalid hardware type */
  256.     }
  257.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP) {
  258.         /* New entry */
  259.         ap = mxallocw(sizeof(struct arp_tab));
  260.         ap->hw_addr = mxallocw(at->hwalen);
  261.         ap->timer.func = arp_drop;
  262.         ap->timer.arg = ap;
  263.         ap->hardware = hardware;
  264.         ap->ip_addr = ipaddr;
  265.         ap->hwalen = at->hwalen;
  266.  
  267.         ap->next = Arp_tab;
  268.         Arp_tab = ap;
  269.     }
  270.     ap->flags = (ap->hardware == ARP_AX25) ? flags : 0;
  271.  
  272.     if(hw_addr == NULLCHAR){
  273.         /* Await response */
  274.         ap->state = ARP_PENDING;
  275.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  276.     } else {
  277.         struct mbuf *bp;
  278.  
  279.         /* Response has come in, update entry and run through queue */
  280.         ap->state = ARP_VALID;
  281.         set_timer(&ap->timer,ARPLIFE * 1000L);
  282.         xfree(ap->hw_addr);
  283.         ap->hw_addr = mxallocw(at->hwalen);
  284.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  285.  
  286.         /* This kludge marks the end of an AX.25 address to allow
  287.          * for optional digipeaters (insert Joan Rivers salute here)
  288.          *
  289.          * changed back to permanent length for use with WNOS routing
  290.          * DB3FL - 1991
  291.          */
  292.         if(hardware == ARP_AX25) {
  293.             ap->hw_addr[ALEN] |= E;
  294.         }
  295.         if(pub) {                    /* leave published entries as published */
  296.             ap->pub = 1;
  297.         }
  298.         while((bp = dequeue(&ap->pending)) != NULLBUF) {
  299.             ip_route(NULLIF,NULLIF,bp,0);
  300.         }
  301.     }
  302.     start_timer(&ap->timer);
  303.     return ap;
  304. }
  305.  
  306. /* Remove an entry from the ARP table */
  307. void
  308. arp_drop(void *p)
  309. {
  310.     struct arp_tab *ap = p, *app, *aplast = NULLARP;
  311.  
  312.     for(app = Arp_tab; app != NULLARP; aplast = app, app = app->next) {
  313.         if(app == ap)
  314.             break;
  315.     }
  316.     if(app == NULLARP)
  317.         return;
  318.  
  319.     if(aplast != NULLARP)
  320.         aplast->next = app->next;
  321.     else
  322.         Arp_tab = app->next;
  323.  
  324.     /* Timer should already be stopped, but just in case... */
  325.     stop_timer(&app->timer);
  326.  
  327.     free_q(&app->pending);
  328.     xfree(app->hw_addr);
  329.     xfree(app);
  330. }
  331.  
  332. /* Look up the given IP address in the ARP table */
  333. struct arp_tab *
  334. arp_lookup(int16 hardware,int32 ipaddr)
  335. {
  336.     struct arp_tab *ap, *aplast = NULLARP;
  337.  
  338.     for(ap = Arp_tab; ap != NULLARP; aplast = ap, ap = ap->next) {
  339.         if(ap->ip_addr == ipaddr && ap->hardware == hardware) {
  340.             if(aplast != NULLARP) {
  341.                 /* Move to top of list */
  342.                 aplast->next = ap->next;
  343.                 ap->next = Arp_tab;
  344.                 Arp_tab = ap;
  345.             }
  346.             return ap;
  347.         }
  348.     }
  349.     return NULLARP;
  350. }
  351.  
  352. /* Convert an incoming ARP packet into a host-format structure */
  353. int
  354. ntoharp(struct arp *arp,struct mbuf **bpp)
  355. {
  356.     if(arp == NULL || bpp == NULLBUFP) {
  357.         return -1;
  358.     }
  359.     arp->hardware = pull16(bpp);
  360.     arp->protocol = pull16(bpp);
  361.     arp->hwalen = PULLCHAR(bpp);
  362.     arp->pralen = PULLCHAR(bpp);
  363.     arp->opcode = pull16(bpp);
  364.     pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  365.     arp->sprotaddr = pull32(bpp);
  366.     pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  367.     arp->tprotaddr = pull32(bpp);
  368.  
  369.     /* Get rid of anything left over */
  370.     free_p(*bpp);
  371.     *bpp = NULLBUF;
  372.     return 0;
  373. }
  374.  
  375.